import { Inject, Provide } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository, Not, In } from "typeorm";
import { RoleEntity } from "@entity/system/role.entity";
import { UserEntity } from "@entity/system/user.entity";
import { UserRoleEntity } from "@entity/system/userRole.entity";
import { DeptEntity } from "@entity/system/dept.entity";
import { RoleMenuEntity } from "@entity/system/roleMenu.entity";
import {
  ListRoleDTO,
  CreateRoleDTO,
  UpdateRoleDTO,
  CancelAuthUserDTO,
  BatchCancelAuthUserDTO,
  ListAuthUserDTO,
  BatchBindAuthUserDTO
} from "@dto/system/role.dto";
import { resBuild } from "@utils/resBuild";
import { checkKeyIsExist, checkUpdateKeyRepeat } from "@utils/serviceHelp";
import { getOperator } from "@utils";

@Provide()
export class RoleService {
  @Inject()
  ctx: Context;

  @InjectEntityModel(RoleEntity)
  protected roleEntity: Repository<RoleEntity>;

  @InjectEntityModel(UserEntity)
  protected userEntity: Repository<UserEntity>;

  @InjectEntityModel(UserRoleEntity)
  protected userRoleEntity: Repository<UserRoleEntity>;

  @InjectEntityModel(DeptEntity)
  protected deptEntity: Repository<DeptEntity>;

  @InjectEntityModel(RoleMenuEntity)
  protected roleMenuEntity: Repository<RoleMenuEntity>;

  // 列表
  async list(queryParams: ListRoleDTO) {
    const queryBuilder = this.roleEntity.createQueryBuilder('entity');

    if(queryParams.roleName) {
      queryBuilder.andWhere(`entity.roleName LIKE "%${queryParams.roleName}%"`)
    }
    if(queryParams.roleKey) {
      queryBuilder.andWhere(`entity.roleKey LIKE "%${queryParams.roleKey}%"`)
    }
    if(queryParams.status) {
      queryBuilder.andWhere(`entity.status = ${queryParams.status}`)
    }
    // 时间范围，包含全天
    if(queryParams["params[beginTime]"] && queryParams["params[endTime]"]) {
      queryBuilder.andWhere(`entity.createTime BETWEEN :beginTime AND :endTime`, {
        beginTime: queryParams["params[beginTime]"] + ' 00:00:00',
        endTime: queryParams["params[endTime]"] + ' 23:59:59',
      })
    }

    if(queryParams.pageNum && queryParams.pageSize) {
      queryBuilder.skip((queryParams.pageNum - 1) * queryParams.pageSize).take(queryParams.pageSize)
    }

    queryBuilder.addOrderBy('entity.roleSort', 'ASC')
    queryBuilder.addOrderBy('entity.createTime', 'DESC')

    const [rows, total] = await queryBuilder.getManyAndCount()
    return resBuild.list(rows, total)
  }

  // 添加
  async create(role: CreateRoleDTO) {
    // 新增之前先判断是否已存在
    await checkKeyIsExist(this.roleEntity,'roleName', role.roleName)
    await checkKeyIsExist(this.roleEntity,'roleKey', role.roleKey)

    // 新增角色基础信息，关联菜单信息
    const myEntity = this.roleEntity.create(role);
    myEntity.setCreateBy(getOperator(this.ctx))
    const addResult = await this.roleEntity.save(myEntity);

    // 添加角色和菜单关联信息
    await this.roleConnectWithMenu(addResult.roleId, role.menuIds)
    return resBuild.success()
  }

  // 删除
  async delete(roleId: string) {
    const ids = roleId.split(',').map(id => Number(id));
    await this.roleEntity.delete(ids);
    return resBuild.success()
  }

  // 修改，修改角色时，关联菜单信息
  async update(role: UpdateRoleDTO) {
    // 先判断是否已存在
    await checkUpdateKeyRepeat(this.roleEntity,'roleName', role.roleName)
    await checkUpdateKeyRepeat(this.roleEntity,'roleKey', role.roleKey)

    // 首先处理角色基础信息的更新
    const myEntity = this.roleEntity.create(role);
    myEntity.setUpdateBy(getOperator(this.ctx))
    await this.roleEntity.save(role);

    // 先删除角色和菜单关联信息，再重新添加
    await this.roleMenuEntity.delete({
      roleId: role.roleId
    })

    // 重新添加角色和菜单关联信息
    await this.roleConnectWithMenu(role.roleId, role.menuIds)

    return resBuild.success()
  }

  // 详情
  async detail(roleId: number) {
    const detailInfo = await this.roleEntity.findOneBy({
      roleId,
    });
    return resBuild.data(detailInfo)
  }

  // 已分配的用户列表
  async allocatedUserList(body: ListAuthUserDTO) {
    const roleHasUserIds = await this.userRoleEntity.find({
      select: ['userId'],
      where: {
        roleId: body.roleId
      }
    })
    const userIds = roleHasUserIds.map(item => item.userId)
    const entity = this.userEntity.createQueryBuilder('user');
    entity.where('user.status = :status', { status: '0' })
    entity.andWhere('user.userId IN (:...userIds)', { userIds: userIds });
    if(body.userName) {
      entity.andWhere(`user.userName LIKE "%${body.userName}%"`)
    }
    if(body.phonenumber) {
      entity.andWhere(`user.phonenumber LIKE "%${body.phonenumber}%"`)
    }
    entity.skip((body.pageNum - 1) * body.pageSize).take(body.pageSize)
    entity.leftJoinAndMapOne('user.dept', DeptEntity , 'dept', 'user.deptId = dept.deptId')

    const [ rows, total ] = await entity.getManyAndCount()
    return resBuild.list(rows, total)
  }

  // 未分配的用户列表
  async unallocatedUserList(body: ListAuthUserDTO) {
    const roleHasUserIds = await this.userRoleEntity.find({
      select: ['userId'],
      where: {
        roleId: body.roleId
      }
    })
    const userIds = roleHasUserIds.map(item => item.userId)
    const entity = this.userEntity.createQueryBuilder('user');
    entity.where('user.status = :status', { status: '0' })
    entity.andWhere({
      userId: Not(In(userIds)),
    })
    if(body.userName) {
      entity.andWhere(`user.userName LIKE "%${body.userName}%"`)
    }
    if(body.phonenumber) {
      entity.andWhere(`user.phonenumber LIKE "%${body.phonenumber}%"`)
    }
    entity.skip((body.pageNum - 1) * body.pageSize).take(body.pageSize)
    entity.leftJoinAndMapOne('user.dept', DeptEntity , 'dept', 'user.deptId = dept.deptId')

    const [ rows, total ] = await entity.getManyAndCount()
    return resBuild.list(rows, total)
  }

  // 取消授权用户
  async cancelAuthUser(body: CancelAuthUserDTO) {
    await this.userRoleEntity.delete({
      roleId: body.roleId,
      userId: body.userId
    })
    return resBuild.success()
  }

  // 批量 取消授权用户
  async batchCancelAuthUser(body: BatchCancelAuthUserDTO) {
    const userIds = body.userIds.split(',').map(id => Number(id));
    await this.userRoleEntity.delete({
      roleId: body.roleId,
      userId: In(userIds)
    })
    return resBuild.success()
  }

  // 批量授权绑定用户
  async batchBindAuthUser(body: BatchBindAuthUserDTO) {
    const userIds = body.userIds.split(',').map(id => Number(id));
    const userRoleList = userIds.map(userId => {
      return {
        roleId: body.roleId,
        userId
      }
    })
    await this.userRoleEntity.save(userRoleList)
    return resBuild.success()
  }

  /** -------------以下为辅助函数--------------- */
  // 角色和菜单的关联
  async roleConnectWithMenu(roleId: number, menuIds: number[]) {
    const roleMenuList = menuIds.map(menuId => {
      return {
        roleId,
        menuId
      }
    })
    await this.roleMenuEntity.save(roleMenuList)
  }
}
